import java.util.Collection;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Authors - Oren Bracha, Rony Lahav & Yehuda Eterman
 *
 * DBCopy - it is the copy of the DB, it can only do actions that do not change the DB  
 */
public class DBCopy implements DBInterface{
	
	public DBCopy(SortedMap<String, DBTuple> toCopyFrom){
		//tuplesMap
		tuplesMap = toCopyFrom;
	}
	
	/**
	 * This method returns the next fragment number I want to ask for a specific picture(spcific peer)
	 */
	public String getNumberOfNextPicSegment(String peerName){
		DBTuple tuple = tuplesMap.get(peerName);
		if(tuple == null){
			return null;
		}
		int nextSegment = tuple.getIncompletePicture().size() + 1;
		
		return Integer.toString(nextSegment);
	}
	
	/** This method gets the number of peers that have the complete picture of a specific peer 
	 * and divide it by the parameter N and returns the result
	 */
	public float findProbabiltyForPictureUpdate(String peerName){
		DBTuple tuple = tuplesMap.get(peerName);
		if(tuple == null){
			return -1;
		}
		int countOfPeers = tuple.getCountOfPeersWithNewPic();
		return (float)countOfPeers / (float)proj350.getNParameter();
	}
	
	/**
	 * return all tuples in DB
	 */
	public synchronized SortedMap<String, DBTuple> getAllTuples(){
		return tuplesMap;
	}
	
	/**
	 * This method gets a peername and returns the list of all the peers that this peername is in
	 * their list (has their picture) 
	 */
	public String[] findPeersThatHavePeerInPicSet(String peerName){
		String result = "";
		Collection<DBTuple> c = tuplesMap.values();
		
		for (DBTuple tuple : c) {
			if(tuple.checkIfPeerInSet(peerName)){
				result += tuple.getPeerName() + ",";
			}
		}

		return result.split(",");
	}
	
	/**
	 * Return all tuples in DB that are OnLine (but the requesting peer) 
	 */
	public SortedMap<String, DBTuple> getAllTuplesForUpdate(){
		SortedMap<String, DBTuple> newMap = new TreeMap<String, DBTuple>();
		
		Collection<DBTuple> c = tuplesMap.values();
		
		for (DBTuple tuple : c) {
			if (tuple.getStatus() && tuple.getPeerName().compareTo(proj350.getMyPeerName()) != 0) {
				newMap.put(tuple.getPeerName(), tuple);
			}
		}
		return newMap;
	}
	
	/**
	 * @param PeerName - peer to start from
	 * @return all tuples in DB from the peerName parameter and further
	 */
	public SortedMap<String, DBTuple> getTuplesFromPeer(String peerName){
		SortedMap<String, DBTuple> headMap = tuplesMap.tailMap(peerName);
		headMap.remove(peerName);
		return headMap;
	}
	
	/**
	 * @param PeerName - peer to end with
	 * @return all tuples in DB until the peerName parameter
	 */
	public SortedMap<String, DBTuple> getTuplesUntilPeer(String peerName){
		return tuplesMap.headMap(peerName);
	}
	

	
	/**
	 * this function takes all the tuples with a DB Version earlier then the given parameter
	 * @param dbVersion - the version to check
	 * @return all the appropriate tuples
	 */
	public SortedMap<String, DBTuple> getTuplesByDbVersion(String dbVersion) {
		if (dbVersion.compareTo("0")==0){
			dbVersion = DateStringConverter.getZeroDateAsString();
		}
		
		long requestedVersion = DateStringConverter.getMSFromStringMessageFormat(dbVersion);
		SortedMap<String, DBTuple> returnValue = new TreeMap<String, DBTuple>();
		//go over all peers and find the peer with later DB Version
		for (DBTuple tuple : tuplesMap.values()) {
			long tupleVersion = DateStringConverter.getMSFromStringMessageFormat(tuple.getPeerCommitTime());
			
			if (requestedVersion < tupleVersion) {
				returnValue.put(tuple.getPeerName(), tuple);
			}
		}
		return returnValue;
	}
	
	/**
	 * 
	 * @return all the tuples in the DB - in TEXT
	 */
	public String asString() {
		String sb = "";
		for (DBTuple tuple : tuplesMap.values()) {
			sb += (MessageCenter.newline + "_______________________" + MessageCenter.newline) + (tuple.toString());
		}

		return sb;
	}

	/**
	 * Returns true if the DB is empty, else otherwise
	 */
	public synchronized boolean isDBEmpty() {
		return tuplesMap.isEmpty();
	}
	
	// return the DB Tuple of the peer
	public synchronized DBTuple findTuple(String PeerName){
		return tuplesMap.get(PeerName);
	}
	
	//we save all of the Peer Tuples in this map
	private SortedMap<String, DBTuple> tuplesMap = new TreeMap<String, DBTuple>();

	/**
	 * This method returns the number of peers that the parameter peer name is in their lisr t (has their picture)
	 */
	public synchronized int findHowManyPeersHaveNewPic(String peerName){
		DBTuple tuple = tuplesMap.get(peerName);
		if(tuple == null){
			return -1;
		}
		return tuple.getCountOfPeersWithNewPic();
	}

	/**
	 * This method gets a "from" peer and a "to" peer and returns all of the peers in the range that have
	 * later commit time than the parameter dbVersion
	 */
	public synchronized SortedMap<String, DBTuple> getRangeOfPeers(String peer1, String peer2, String dbVersion){
		SortedMap<String, DBTuple> smap = null;
		if (peer1.compareTo("0")==0){
			smap = getTuplesUntilPeer(peer2);
		}
		else if (peer2.compareTo("all")==0){
			smap = getTuplesFromPeer(peer2);
		}
		else{
			smap = tuplesMap.tailMap(peer1).headMap(peer2);
			smap.remove(peer1);
			smap.remove(peer2);
		}
		
		SortedMap<String, DBTuple> returnValue = new TreeMap<String, DBTuple>();
		long requestedVersion = DateStringConverter.getMSFromStringMessageFormat(dbVersion);
		//go over all peers and find the peer with later DB Version
		for (DBTuple tuple : tuplesMap.values()) {
			long tupleVersion = DateStringConverter.getMSFromStringMessageFormat(tuple.getPeerCommitTime());
			if (requestedVersion < tupleVersion) {
				returnValue.put(tuple.getPeerName(), tuple);
			}
		}
		
		return returnValue;
	}
	
}
